#include <mboot.h>
#include <vmm.h>

void memcopy(unsigned char *dest, const unsigned char *src, unsigned int len)
{
	for(; len!=0; len--) *dest++ = *src++;
}

void memset(unsigned char *dest, unsigned char val, unsigned int len)
{
	for(; len!=0; len--) *dest++ = val;
}

unsigned int pmm_stack_location = PMM_STACK_ADDRESS;
unsigned int pmm_stack_max = PMM_STACK_ADDRESS;
unsigned int pmm_location;


void init_pmm(unsigned int start)
{
	pmm_paging_active = 0;
	pmm_location = (start + 0x1000) & PAGE_MASK;
}

unsigned int pmm_alloc_page()
{
	if (pmm_paging_active)
	{
		if(pmm_stack_location == PMM_STACK_ADDRESS)
		{
			printf("Error: Out of memory");
			for(;;);
		}
		pmm_stack_location -= sizeof(unsigned int);
		unsigned int *stack = (unsigned int *)pmm_stack_location;
		return *stack;
	} else {
		return pmm_location += 0x1000;
	}
}

void pmm_free_page(unsigned int p)
{
	if(p < pmm_location)
		return;
	if(pmm_stack_max <= pmm_stack_location)
	{
		map(pmm_stack_max, p, PAGE_PRESENT|PAGE_WRITE);
		pmm_stack_max += 0x1000;
	} else {
		unsigned int *stack  = (unsigned int *)pmm_stack_location;
		*stack = p;
		pmm_stack_location += sizeof(unsigned int);
	}
}

void fill_memorymap()
{

	extern mboot_info *kernel_multiboot;
	unsigned int i = kernel_multiboot->mmap_addr + 0xC0000000;
	while(i < kernel_multiboot->mmap_addr + 0xC0000000 + kernel_multiboot->mmap_length)
	{
		mmap_entry *me = (mmap_entry *) i;

		if (me->type == 1)
		{
			unsigned int j;
			for(j = me->base_addr_lower; j < me->base_addr_lower+me->length_lower; j+= 0x1000)
			{
				pmm_free_page(j);
			}
		}
		i += me->size + sizeof(unsigned int);
	}
}
